package com.esayread.reader

import android.content.Context
import android.util.Log
import com.esayread.data.BookFormat
import com.tom_roush.pdfbox.android.PDFBoxResourceLoader
import com.tom_roush.pdfbox.pdmodel.PDDocument
import com.tom_roush.pdfbox.text.PDFTextStripper
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import java.io.*
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

/**
 * 电子书阅读器，支持EPUB、PDF、MOBI格式
 */
class BookReader(private val context: Context) {
    
    companion object {
        private const val TAG = "BookReader"
    }
    
    init {
        // 初始化PDFBox
        PDFBoxResourceLoader.init(context)
    }
    
    /**
     * 读取电子书内容
     */
    suspend fun readBook(filePath: String, format: BookFormat): BookContent = withContext(Dispatchers.IO) {
        try {
            when (format) {
                BookFormat.EPUB -> readEpubContent(filePath)
                BookFormat.PDF -> readPdfContent(filePath)
                BookFormat.MOBI -> readMobiContent(filePath)
            }
        } catch (e: Exception) {
            Log.e(TAG, "Error reading book: ${e.message}", e)
            BookContent(
                title = "读取失败",
                chapters = listOf(
                    Chapter(
                        title = "错误",
                        content = "无法读取电子书内容：${e.message}"
                    )
                )
            )
        }
    }
    
    // 缓存已解析的章节内容
    private val chapterCache = mutableMapOf<String, Chapter>()
    private val imageCache = mutableMapOf<String, String>() // Base64缓存
    
    // 缓存文件内容用于懒加载
    private var cachedFileContents = mutableMapOf<String, String>()
    private var cachedImageFiles = mutableMapOf<String, ByteArray>()
    private var currentBookPath = ""
    
    /**
     * 读取EPUB格式内容 - 优化版本，实现懒加载
     */
    private suspend fun readEpubContent(filePath: String): BookContent {
        val chapters = mutableListOf<Chapter>()
        var bookTitle = "未知书籍"
        var tableOfContents = mutableListOf<TocItem>()
        
        try {
            val file = File(filePath)
            val zipInputStream = ZipInputStream(FileInputStream(file))
            var entry: ZipEntry?
            
            // 存储所有文件内容
            val fileContents = mutableMapOf<String, String>()
            val imageFiles = mutableMapOf<String, ByteArray>()
            val htmlFiles = mutableListOf<String>()
            var opfPath = ""
            var ncxPath = ""
            
            while (zipInputStream.nextEntry.also { entry = it } != null) {
                val entryName = entry!!.name
                
                if (!entry!!.isDirectory) {
                    if (entryName.endsWith(".jpg") || entryName.endsWith(".jpeg") || 
                        entryName.endsWith(".png") || entryName.endsWith(".gif") ||
                        entryName.endsWith(".svg")) {
                        // 存储图片文件
                        imageFiles[entryName] = zipInputStream.readBytes()
                    } else {
                        val content = zipInputStream.readBytes().toString(Charsets.UTF_8)
                        fileContents[entryName] = content
                        
                        // 收集HTML/XHTML文件
                        if (entryName.endsWith(".html") || entryName.endsWith(".xhtml") || entryName.endsWith(".htm")) {
                            htmlFiles.add(entryName)
                        }
                        
                        // 记录OPF文件路径
                        if (entryName.endsWith(".opf")) {
                            opfPath = entryName
                        }
                        
                        // 记录NCX文件路径（目录文件）
                        if (entryName.endsWith(".ncx")) {
                            ncxPath = entryName
                        }
                    }
                }
            }
            zipInputStream.close()
            
            // 解析OPF文件获取书名和阅读顺序
            if (opfPath.isNotEmpty()) {
                val opfContent = fileContents[opfPath] ?: ""
                try {
                    val doc = Jsoup.parse(opfContent)
                    val titleElement = doc.select("dc|title, title").first()
                    if (titleElement != null) {
                        bookTitle = titleElement.text()
                    }
                    
                    // 获取spine中的阅读顺序
                    val spineItems = doc.select("spine itemref")
                    val orderedHtmlFiles = mutableListOf<String>()
                    spineItems.forEach { item ->
                        val idref = item.attr("idref")
                        val manifestItem = doc.select("manifest item[id=$idref]").first()
                        if (manifestItem != null) {
                            val href = manifestItem.attr("href")
                            val fullPath = resolveRelativePath(opfPath, href)
                            if (fileContents.containsKey(fullPath)) {
                                orderedHtmlFiles.add(fullPath)
                            }
                        }
                    }
                    
                    if (orderedHtmlFiles.isNotEmpty()) {
                        htmlFiles.clear()
                        htmlFiles.addAll(orderedHtmlFiles)
                    }
                } catch (e: Exception) {
                    Log.w(TAG, "Error parsing OPF file: ${e.message}")
                }
            }
            
            // 解析NCX文件获取目录
            if (ncxPath.isNotEmpty()) {
                val ncxContent = fileContents[ncxPath] ?: ""
                try {
                    val doc = Jsoup.parse(ncxContent)
                    val navPoints = doc.select("navPoint")
                    navPoints.forEach { navPoint ->
                        val label = navPoint.select("navLabel text").first()?.text() ?: ""
                        val src = navPoint.select("content").first()?.attr("src") ?: ""
                        if (label.isNotEmpty() && src.isNotEmpty()) {
                            // 将NCX中的相对路径转换为绝对路径
                            val absoluteHref = resolveRelativePath(ncxPath, src)
                            Log.d(TAG, "TOC item: '$label' -> original: '$src', resolved: '$absoluteHref'")
                            Log.d(TAG, "NCX解析: 原始href=$src -> 绝对路径=$absoluteHref")
                            tableOfContents.add(TocItem(label, absoluteHref))
                        }
                    }
                } catch (e: Exception) {
                    Log.w(TAG, "Error parsing NCX file: ${e.message}")
                }
            }
            
            // 基于目录结构创建章节 - 为每个目录项创建独立章节
            Log.d(TAG, "=== 开始基于目录创建章节 ===")
            Log.d(TAG, "目录项数量: ${tableOfContents.size}")
            
            if (tableOfContents.isNotEmpty()) {
                // 为每个目录项创建对应的章节
                tableOfContents.forEachIndexed { index, tocItem ->
                    try {
                        Log.d(TAG, "处理目录项[$index]: ${tocItem.title} -> ${tocItem.href}")
                        
                        // 解析href，分离文件路径和锚点
                        val cleanHref = tocItem.href.substringBefore("#")
                        val anchor = if (tocItem.href.contains("#")) tocItem.href.substringAfter("#") else null
                        
                        Log.d(TAG, "文件路径: $cleanHref, 锚点: $anchor")
                        
                        // 查找对应的HTML文件内容
                        val htmlContent = fileContents[cleanHref] ?: ""
                        if (htmlContent.isNotEmpty()) {
                            // 处理HTML内容中的图片路径
                            val doc = Jsoup.parse(htmlContent)
                            val bodyElement = doc.body()
                            
                            if (bodyElement != null) {
                                bodyElement.select("img").forEach { img ->
                                    val src = img.attr("src")
                                    if (src.isNotEmpty()) {
                                        val fullImagePath = resolveRelativePath(cleanHref, src)
                                        if (imageFiles.containsKey(fullImagePath)) {
                                            val imageBytes = imageFiles[fullImagePath]!!
                                            val base64 = android.util.Base64.encodeToString(imageBytes, android.util.Base64.DEFAULT)
                                            val mimeType = getMimeType(fullImagePath)
                                            val dataUrl = "data:$mimeType;base64,$base64"
                                            img.attr("src", dataUrl)
                                        }
                                    }
                                }
                            }
                            
                            // 如果有锚点，尝试提取锚点对应的内容段落
                            val chapterContent = if (anchor != null) {
                                extractContentByAnchor(doc.html(), anchor) ?: doc.html()
                            } else {
                                doc.html()
                            }
                            
                            chapters.add(
                                Chapter(
                                    title = tocItem.title,
                                    content = chapterContent,
                                    isHtml = true,
                                    filePath = tocItem.href // 保存完整的href（包含锚点）
                                )
                            )
                            
                            Log.d(TAG, "创建章节: ${tocItem.title} (${chapterContent.length} chars)")
                        } else {
                            Log.w(TAG, "HTML文件内容不存在: $cleanHref")
                            // 创建一个基本章节
                            chapters.add(
                                Chapter(
                                    title = tocItem.title,
                                    content = "章节内容加载失败：文件不存在",
                                    isHtml = false,
                                    filePath = tocItem.href
                                )
                            )
                        }
                    } catch (e: Exception) {
                        Log.e(TAG, "处理目录项失败 ${tocItem.title}: ${e.message}")
                        // 即使出错也要添加一个章节，保持索引一致性
                        chapters.add(
                            Chapter(
                                title = tocItem.title,
                                content = "章节内容加载失败: ${e.message}",
                                isHtml = false,
                                filePath = tocItem.href
                            )
                        )
                    }
                }
            } else {
                // 如果没有目录，回退到按HTML文件创建章节
                htmlFiles.forEachIndexed { index, fileName ->
                    val htmlContent = fileContents[fileName] ?: ""
                    try {
                        val doc = Jsoup.parse(htmlContent)
                        
                        // 提取章节标题
                        val chapterTitle = doc.select("h1, h2, h3, title").first()?.text() 
                            ?: "第${index + 1}章"
                        
                        // 创建懒加载章节，但保留原始内容作为回退
                        val bodyElement = doc.body()
                        val fallbackContent = if (bodyElement != null) {
                            // 处理图片路径
                            bodyElement.select("img").forEach { img ->
                                val src = img.attr("src")
                                if (src.isNotEmpty()) {
                                    val fullImagePath = resolveRelativePath(fileName, src)
                                    if (imageFiles.containsKey(fullImagePath)) {
                                        val imageBytes = imageFiles[fullImagePath]!!
                                        val base64 = android.util.Base64.encodeToString(imageBytes, android.util.Base64.DEFAULT)
                                        val mimeType = getMimeType(fullImagePath)
                                        val dataUrl = "data:$mimeType;base64,$base64"
                                        img.attr("src", dataUrl)
                                    }
                                }
                            }
                            bodyElement.html()
                        } else {
                            doc.html()
                        }
                        
                        chapters.add(
                            Chapter(
                                title = chapterTitle,
                                content = fallbackContent,
                                isHtml = true,
                                filePath = fileName
                            )
                        )
                    } catch (e: Exception) {
                        Log.w(TAG, "Error parsing HTML file $fileName: ${e.message}")
                        chapters.add(
                            Chapter(
                                title = "第${index + 1}章",
                                content = htmlContent,
                                isHtml = true,
                                filePath = fileName
                            )
                        )
                    }
                }
            }
            
            // 存储文件内容和图片用于懒加载
            this.cachedFileContents = fileContents
            this.cachedImageFiles = imageFiles
            this.currentBookPath = filePath
            
        } catch (e: Exception) {
            Log.e(TAG, "Error reading EPUB: ${e.message}", e)
            throw e
        }
        
        if (chapters.isEmpty()) {
            chapters.add(
                Chapter(
                    title = "内容",
                    content = "未能解析到有效的章节内容"
                )
            )
        }
        
        return BookContent(
            title = bookTitle,
            chapters = chapters,
            tableOfContents = tableOfContents
        )
    }
    
    /**
     * 懒加载章节内容
     */
    suspend fun loadChapterContent(chapter: Chapter): Chapter = withContext(Dispatchers.IO) {
        // 如果章节已有内容或不是HTML格式，直接返回
        if (chapter.content.isNotEmpty() || !chapter.isHtml || chapter.filePath.isEmpty()) {
            return@withContext chapter
        }
        
        // 检查缓存
        val cacheKey = "${currentBookPath}_${chapter.filePath}"
        chapterCache[cacheKey]?.let { cachedChapter ->
            return@withContext cachedChapter
        }
        
        try {
            val htmlContent = cachedFileContents[chapter.filePath] ?: ""
            if (htmlContent.isEmpty()) {
                Log.w(TAG, "No cached content found for ${chapter.filePath}")
                // 返回带有错误信息的章节，而不是空章节
                return@withContext chapter.copy(
                    content = "<p>章节内容加载失败，请重试</p>",
                    isHtml = true
                )
            }
            
            val doc = Jsoup.parse(htmlContent)
            val bodyElement = doc.body()
            
            if (bodyElement != null) {
                // 异步处理图片路径
                bodyElement.select("img").forEach { img ->
                    val src = img.attr("src")
                    if (src.isNotEmpty()) {
                        val fullImagePath = resolveRelativePath(chapter.filePath, src)
                        
                        // 检查图片缓存
                        val imageCacheKey = "${currentBookPath}_${fullImagePath}"
                        val cachedBase64 = imageCache[imageCacheKey]
                        
                        if (cachedBase64 != null) {
                            img.attr("src", cachedBase64)
                        } else if (cachedImageFiles.containsKey(fullImagePath)) {
                            // 异步转换Base64
                            val imageBytes = cachedImageFiles[fullImagePath]!!
                            val base64 = android.util.Base64.encodeToString(imageBytes, android.util.Base64.DEFAULT)
                            val mimeType = getMimeType(fullImagePath)
                            val dataUrl = "data:$mimeType;base64,$base64"
                            
                            // 缓存Base64结果
                            imageCache[imageCacheKey] = dataUrl
                            img.attr("src", dataUrl)
                        } else {
                            Log.w(TAG, "Image not found in cache: $fullImagePath")
                        }
                    }
                }
                
                val processedContent = bodyElement.html()
                if (processedContent.isNotEmpty()) {
                    val loadedChapter = chapter.copy(content = processedContent)
                    
                    // 缓存处理后的章节
                    chapterCache[cacheKey] = loadedChapter
                    
                    return@withContext loadedChapter
                } else {
                    Log.w(TAG, "Processed content is empty for ${chapter.filePath}")
                    return@withContext chapter.copy(
                        content = "<p>章节内容为空</p>",
                        isHtml = true
                    )
                }
            } else {
                Log.w(TAG, "No body element found in ${chapter.filePath}")
                // 如果没有body元素，尝试使用整个文档内容
                val fullContent = doc.html()
                if (fullContent.isNotEmpty()) {
                    val loadedChapter = chapter.copy(content = fullContent)
                    chapterCache[cacheKey] = loadedChapter
                    return@withContext loadedChapter
                } else {
                    return@withContext chapter.copy(
                        content = "<p>无法解析章节内容</p>",
                        isHtml = true
                    )
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "Error loading chapter content for ${chapter.filePath}: ${e.message}", e)
            // 返回带有错误信息的章节
            return@withContext chapter.copy(
                content = "<p>章节加载出错: ${e.message}</p>",
                isHtml = true
            )
        }
    }
    
    /**
     * 读取PDF格式内容 - 增强版本，支持表格和图片
     */
    private suspend fun readPdfContent(filePath: String): BookContent {
        try {
            val file = File(filePath)
            val document = PDDocument.load(file)
            val stripper = PDFTextStripper()
            
            val totalPages = document.numberOfPages
            val chapters = mutableListOf<Chapter>()
            
            // 按页分章节，每5页一个章节以获得更好的阅读体验
            val pagesPerChapter = 5
            val totalChapters = (totalPages + pagesPerChapter - 1) / pagesPerChapter
            
            for (chapterIndex in 0 until totalChapters) {
                val startPage = chapterIndex * pagesPerChapter + 1
                val endPage = minOf((chapterIndex + 1) * pagesPerChapter, totalPages)
                
                stripper.startPage = startPage
                stripper.endPage = endPage
                
                // 保持表格格式和布局
                stripper.setSortByPosition(true)
                stripper.setSpacingTolerance(10f)
                stripper.setAverageCharTolerance(20f)
                
                val rawContent = stripper.getText(document)
                
                // 将PDF内容转换为HTML格式以保持表格和布局
                val htmlContent = convertPdfTextToHtml(rawContent)
                
                chapters.add(
                    Chapter(
                        title = "第${chapterIndex + 1}部分 (页 $startPage-$endPage)",
                        content = htmlContent,
                        isHtml = true // 标记为HTML内容以使用WebView渲染
                    )
                )
            }
            
            document.close()
            
            return BookContent(
                title = file.nameWithoutExtension,
                chapters = chapters
            )
            
        } catch (e: Exception) {
            Log.e(TAG, "Error reading PDF: ${e.message}", e)
            throw e
        }
    }
    
    /**
     * 将PDF文本转换为HTML格式，保持表格和布局
     */
    private fun convertPdfTextToHtml(pdfText: String): String {
        val lines = pdfText.split("\n")
        val htmlBuilder = StringBuilder()
        
        htmlBuilder.append("<div class='pdf-content'>")
        
        var inTable = false
        val tableRows = mutableListOf<String>()
        
        for (line in lines) {
            val trimmedLine = line.trim()
            
            when {
                // 检测表格行（包含多个制表符或多个空格分隔的列）
                isTableRow(trimmedLine) -> {
                    if (!inTable) {
                        inTable = true
                        tableRows.clear()
                    }
                    tableRows.add(trimmedLine)
                }
                
                // 如果之前在表格中，现在不是表格行，则结束表格
                inTable -> {
                    htmlBuilder.append(buildTableHtml(tableRows))
                    inTable = false
                    tableRows.clear()
                    
                    // 处理当前行
                    if (trimmedLine.isNotEmpty()) {
                        htmlBuilder.append(formatTextLine(trimmedLine))
                    }
                }
                
                // 普通文本行
                trimmedLine.isNotEmpty() -> {
                    htmlBuilder.append(formatTextLine(trimmedLine))
                }
                
                // 空行
                else -> {
                    htmlBuilder.append("<br/>")
                }
            }
        }
        
        // 如果文档结束时还在表格中
        if (inTable && tableRows.isNotEmpty()) {
            htmlBuilder.append(buildTableHtml(tableRows))
        }
        
        htmlBuilder.append("</div>")
        return htmlBuilder.toString()
    }
    
    /**
     * 检测是否为表格行
     */
    private fun isTableRow(line: String): Boolean {
        // 检测包含多个制表符或多个连续空格的行
        val tabCount = line.count { it == '\t' }
        val multiSpacePattern = Regex("\\s{3,}")
        val multiSpaceMatches = multiSpacePattern.findAll(line).count()
        
        return tabCount >= 2 || multiSpaceMatches >= 2
    }
    
    /**
     * 构建表格HTML
     */
    private fun buildTableHtml(rows: List<String>): String {
        if (rows.isEmpty()) return ""
        
        val tableBuilder = StringBuilder()
        tableBuilder.append("<table class='pdf-table'>")
        
        rows.forEachIndexed { index, row ->
            val cells = if (row.contains('\t')) {
                row.split('\t')
            } else {
                row.split(Regex("\\s{3,}"))
            }
            
            tableBuilder.append("<tr>")
            cells.forEach { cell ->
                val trimmedCell = cell.trim()
                if (trimmedCell.isNotEmpty()) {
                    val tag = if (index == 0) "th" else "td"
                    tableBuilder.append("<$tag>$trimmedCell</$tag>")
                }
            }
            tableBuilder.append("</tr>")
        }
        
        tableBuilder.append("</table>")
        return tableBuilder.toString()
    }
    
    /**
     * 格式化文本行
     */
    private fun formatTextLine(line: String): String {
        return when {
            // 标题检测（全大写或以数字开头）
            line.matches(Regex("^[0-9]+\\..*")) || line.matches(Regex("^[A-Z\\s]+$")) -> {
                "<h3>$line</h3>"
            }
            // 普通段落
            else -> {
                "<p>$line</p>"
            }
        }
    }
    
    /**
     * 读取MOBI格式内容
     */
    private suspend fun readMobiContent(filePath: String): BookContent {
        // MOBI格式解析比较复杂，这里提供基础实现
        // 实际项目中可能需要使用专门的MOBI解析库
        
        try {
            val file = File(filePath)
            val bytes = file.readBytes()
            
            // 简单的文本提取（实际MOBI格式需要更复杂的解析）
            val content = String(bytes, Charsets.UTF_8)
                .replace("\u0000", "") // 移除空字符
                .replace(Regex("[\\x00-\\x1F\\x7F-\\x9F]"), "") // 移除控制字符
            
            // 尝试提取可读文本
            val readableContent = content
                .split("\n")
                .filter { line -> 
                    line.trim().length > 10 && 
                    line.matches(Regex(".*[a-zA-Z\u4e00-\u9fa5].*")) // 包含字母或中文
                }
                .joinToString("\n")
            
            return BookContent(
                title = file.nameWithoutExtension,
                chapters = listOf(
                    Chapter(
                        title = "正文",
                        content = if (readableContent.isNotBlank()) readableContent 
                                 else "MOBI格式解析功能正在开发中，暂时无法显示内容。"
                    )
                )
            )
            
        } catch (e: Exception) {
            Log.e(TAG, "Error reading MOBI: ${e.message}", e)
            throw e
        }
    }
    
    /**
     * 解析相对路径
     */
    private fun resolveRelativePath(basePath: String, relativePath: String): String {
        val baseDir = basePath.substringBeforeLast('/')
        return if (baseDir.isEmpty()) relativePath else "$baseDir/$relativePath"
    }
    
    /**
     * 根据锚点提取对应的内容段落
     */
    private fun extractContentByAnchor(htmlContent: String, anchor: String): String? {
        try {
            // 查找锚点位置
            val anchorPattern = "id\\s*=\\s*[\"']$anchor[\"']".toRegex(RegexOption.IGNORE_CASE)
            val match = anchorPattern.find(htmlContent)
            
            if (match != null) {
                val anchorPosition = match.range.first
                
                // 从锚点位置开始，查找下一个锚点或文档结束
                val remainingContent = htmlContent.substring(anchorPosition)
                
                // 查找下一个id属性（下一个锚点）
                val nextAnchorPattern = "id\\s*=\\s*[\"'][^\"']+[\"']".toRegex(RegexOption.IGNORE_CASE)
                val nextMatch = nextAnchorPattern.find(remainingContent, 1) // 从位置1开始，跳过当前锚点
                
                val endPosition = if (nextMatch != null) {
                    anchorPosition + nextMatch.range.first
                } else {
                    htmlContent.length
                }
                
                val sectionContent = htmlContent.substring(anchorPosition, endPosition)
                Log.d(TAG, "提取锚点内容: $anchor, 长度: ${sectionContent.length}")
                return sectionContent
            }
        } catch (e: Exception) {
            Log.e(TAG, "提取锚点内容失败 $anchor: ${e.message}")
        }
        
        return null
    }
    
    /**
     * 根据文件扩展名获取MIME类型
     */
    private fun getMimeType(filePath: String): String {
        return when (filePath.substringAfterLast('.').lowercase()) {
            "jpg", "jpeg" -> "image/jpeg"
            "png" -> "image/png"
            "gif" -> "image/gif"
            "svg" -> "image/svg+xml"
            else -> "image/jpeg"
        }
    }
}

/**
 * 电子书内容数据类
 */
data class BookContent(
    val title: String,
    val chapters: List<Chapter>,
    val tableOfContents: List<TocItem> = emptyList()
) {
    companion object {
        private const val TAG = "BookContent"
    }
    /**
     * 获取总字符数
     */
    fun getTotalCharacters(): Int {
        return chapters.sumOf { it.content.length }
    }
    
    /**
     * 根据字符位置获取章节索引
     */
    fun getChapterIndexByPosition(position: Int): Int {
        var currentPosition = 0
        chapters.forEachIndexed { index, chapter ->
            currentPosition += chapter.content.length
            if (position <= currentPosition) {
                return index
            }
        }
        return chapters.size - 1
    }
    
    /**
     * 根据章节索引和章节内位置获取全书位置
     */
    fun getGlobalPosition(chapterIndex: Int, chapterPosition: Int): Int {
        var globalPosition = 0
        for (i in 0 until chapterIndex.coerceAtMost(chapters.size)) {
            globalPosition += chapters[i].content.length
        }
        return globalPosition + chapterPosition
    }
    
    /**
     * 根据目录href查找对应的章节索引
     */
    fun findChapterByHref(href: String): Int {
        Log.d(TAG, "=== 开始查找章节 ===")
        Log.d(TAG, "目标href: $href")
        Log.d(TAG, "总章节数: ${chapters.size}")
        
        // 打印所有章节的filePath用于调试
        Log.d(TAG, "=== 所有章节信息 ===")
        chapters.forEachIndexed { index, chapter ->
            Log.d(TAG, "章节[$index]: title=${chapter.title}, filePath=${chapter.filePath}")
        }
        
        if (chapters.isEmpty()) {
            Log.w(TAG, "No chapters available")
            return 0
        }
        
        // 1. 精确匹配（包含锚点的完整href）
        chapters.forEachIndexed { index, chapter ->
            if (chapter.filePath.isNotEmpty() && chapter.filePath == href) {
                Log.d(TAG, "找到精确匹配，索引: $index, filePath: ${chapter.filePath}")
                return index
            }
        }
        
        // 2. 清理href后的匹配（移除查询参数但保留锚点）
        val cleanHref = href.substringBefore("?")
        if (cleanHref != href) {
            chapters.forEachIndexed { index, chapter ->
                if (chapter.filePath.isNotEmpty() && chapter.filePath == cleanHref) {
                    Log.d(TAG, "找到清理后匹配，索引: $index, filePath: ${chapter.filePath}")
                    return index
                }
            }
        }
        
        // 3. 文件名匹配（忽略锚点，用于向后兼容）
        val fileOnlyHref = href.substringBefore("#").substringBefore("?")
        chapters.forEachIndexed { index, chapter ->
            if (chapter.filePath.isNotEmpty()) {
                val chapterFileName = chapter.filePath.substringBefore("#").substringBefore("?")
                if (chapterFileName == fileOnlyHref) {
                    Log.d(TAG, "找到文件名匹配，索引: $index, 文件: $chapterFileName")
                    return index
                }
            }
        }
        
        // 4. 模糊文件名匹配
        chapters.forEachIndexed { index, chapter ->
            if (chapter.filePath.isNotEmpty()) {
                val chapterFileName = File(chapter.filePath.substringBefore("#")).name
                val targetFileName = File(fileOnlyHref).name
                if (chapterFileName.equals(targetFileName, ignoreCase = true)) {
                    Log.d(TAG, "找到模糊文件名匹配，索引: $index, 文件: $chapterFileName")
                    return index
                }
            }
        }
        
        // 5. 章节标题匹配
        val hrefFileName = File(fileOnlyHref).nameWithoutExtension
        chapters.forEachIndexed { index, chapter ->
            if (chapter.title.contains(hrefFileName, ignoreCase = true)) {
                Log.d(TAG, "找到标题匹配，索引: $index, 标题: ${chapter.title}")
                return index
            }
        }
        
        // 如果都没找到，返回0作为默认（第一章）
        Log.e(TAG, "=== 章节匹配失败 ===")
        Log.e(TAG, "目标href: $href")
        Log.e(TAG, "所有匹配策略都失败，返回默认索引0")
        return 0
    }
}

/**
 * 章节数据类
 */
data class Chapter(
    val title: String,
    val content: String,
    val isHtml: Boolean = false,
    val filePath: String = "" // 用于懒加载的文件路径
)

/**
 * 目录项数据类
 */
data class TocItem(
    val title: String,
    val href: String
)